package pac

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"regexp"
	"slgw_web/serial/dto"
	"slgw_web/serial/util"
	"strconv"
	"time"

	"github.com/jacobsa/go-serial/serial"
	models "openzbox.com/frame/echo/models/sl_gw01"
)

//var stopTimerCh = make(chan struct{})

func init() {
	GetSerialInit()
	GetSerial_SlavelInit()
	Serial_Slave_DetailInit()
	Cj188Client()
	GetCj188data()
}
func Cj188Restart(id int64) {
	if !util.StopRestart { //是否禁止重连
		for i, _ := range Test {
			if Test[i].DataID == id {
				Test[i].CJ188Port.Close()
				//重连
				CJ188Port, err := serial.Open(Test[i].Options)
				if err != nil {
					util.Error("PortName:" + Test[i].ComName + ",DLT645串口开启失败:" + err.Error())
					return
				}
				//成功
				newData := dto.CollectSet{
					CJ188Port:  CJ188Port,
					DataID:     id,
					ComName:    Test[i].ComName,
					Options:    Test[i].Options,
					IsEnd:      true,
					DLTisSend:  true,
					SerialID:   Test[i].SerialID,
					TPITV:      Test[i].TPITV,
					Timeout:    Test[i].Timeout,
					RetryCount: Test[i].RetryCount,
				}
				util.Error("PortName:" + Test[i].ComName + ",DLT645串口重启成功")
				// 找到匹配的数据，将其替换为新的数据
				Test[i] = newData
				break // 找到后退出循环
			}
		}
	}
}

// 串口初始化
func Cj188Client() {
	//Test = Test[:0]
	for _, data := range util.Serial {
		if data.Agreement == "5" { //cj188模式
			baudRate, err := strconv.Atoi(data.BAD)
			if err != nil {
				util.Error(data.ComName + "的波特率转换失败")
			}
			dataBits, err := strconv.Atoi(data.DAB)
			if err != nil {
				util.Error(data.ComName + "的数据位转换失败")
			}
			stopBits, err := strconv.Atoi(data.STO)
			if err != nil {
				util.Error(data.ComName + "的停止位转换失败")
			}
			var parityMode serial.ParityMode
			if data.CHC == "N" {
				parityMode = 0

			} else if data.CHC == "O" {
				parityMode = 1
			} else {
				parityMode = 2
			}
			options := serial.OpenOptions{
				BaudRate:              uint(baudRate),
				DataBits:              uint(dataBits),
				StopBits:              uint(stopBits),
				InterCharacterTimeout: 100,
				PortName:              data.ComName,
				ParityMode:            parityMode,
				//MinimumReadSize: 0,
			} //初始化结构体变量
			CJ188Port, err := serial.Open(options)
			if err != nil {
				util.Error("PortName:" + data.ComName + ",CJ188串口开启失败:" + err.Error())
				return
			}
			if data.TPITV == "" || data.TPITV == "0" {
				data.TPITV = "60"

			}
			tpitv, err := strconv.Atoi(data.TPITV)
			if err != nil {
				util.Error(data.ComName + "的采集周期时间配置错误,将默认为60秒")
				tpitv = 60
			}
			cj188 := dto.CollectSet{
				CJ188Port:  CJ188Port,
				DataID:     data.ID,
				ComName:    data.ComName,
				Options:    options,
				IsEnd:      true,
				DLTisSend:  true,
				SerialID:   data.ID,
				TPITV:      tpitv,
				Timeout:    int(data.Timeout),
				RetryCount: data.RetryCount,
			}
			// lock := dto.DLT645Lock{
			// 	DLTisSend: true,
			// 	SerialID:  data.ID,
			// }
			Test = append(Test, cj188)
			// util.DLT645Lock = append(util.DLT645Lock, lock)
			// fmt.Println("util.DLT645Data", util.DLT645Data)
			// fmt.Println("util.DLT645Lock", util.DLT645Lock)
		}
	}
}

// 获取返回的参数
func GetCj188data() {
	for i := range Test {
		i2 := i
		//获取返回的参数
		if Test[i2].CJ188Port != nil {
			go func() {
				receivedData := false
				buffer := make([]byte, 0)

				for {
					buf := make([]byte, 68)
					n, err := Test[i2].CJ188Port.Read(buf)
					if err != nil {
						fmt.Println("串口：" + Test[i2].ComName + ",cj188获取参数错误:" + err.Error())
						time.Sleep(10 * time.Second)
					} else {
						if n == 0 {
							if receivedData {
								//fmt.Printf("%x", buffer)      // 输出已拼接的 buffer
								dataStr := BytesToHex(buffer) //获取字符串参数
								//fmt.Println("dlt645返回参数:", dataStr)
								dataS := analysisDataCJ188(dataStr)
								if dataS == "" {
									buffer = make([]byte, 0) // 重置 buffer
									receivedData = false
									Test[i2].DLTisSend = true
									//stopTimerCh <- struct{}{}
									util.Error("cj188协议采集错误,返回参数解析失败 ComName:" + Test[i2].ComName + ",参数：" + dataStr)
								} else {

									cj188Type := dataS[0:2] //仪表类型
									datareal := ""          //返回的数据
									unit := ""              //单位
									addressID := dataS[2:16]
									var serial_Slave_ID int64 = 0
									hexString := ""
									vString := ""
									value3 := ""
									var item models.Serial_Slave_Detail
									//获取serial_slave_id
									for _, serial_Slave := range util.Serial_Slave {
										if serial_Slave.IsCollect == 1 {
											//获取反转的地址位
											modbusSlaveID := ChangeStr(serial_Slave.ModbusSlaveID)
											if modbusSlaveID == addressID && serial_Slave.CJ188Type != nil {
												if serial_Slave.CJ188UnitType == nil {
													*serial_Slave.CJ188UnitType = 2
												}
												serial_Slave_ID = serial_Slave.ID

												//加上小数点偏移后计算最终值
												CJ188DecimalPointOffset := 0

												for _, serial_Slave_Detail := range util.Serial_Slave_Detail {
													if serial_Slave_Detail.Serial_ID == serial_Slave.Serial_ID && serial_Slave_Detail.Serial_Slave_ID == serial_Slave_ID {
														//累计用量
														CJ188DecimalPointOffset = *serial_Slave_Detail.CJ188DecimalPointOffset
														// item = serial_Slave_Detail
														item = serial_Slave_Detail

														if *serial_Slave_Detail.CJ188CType == 1 { //累计用量
															if cj188Type == "10" {
																if *serial_Slave.CJ188UnitType == 1 { //单位在前面
																	datareal = dataS[28:36]
																	unit = dataS[26:28]
																} else {
																	datareal = dataS[26:34]
																	unit = dataS[34:36]
																}
															}
														} else if *serial_Slave_Detail.CJ188CType == 2 { //本月用量
															if cj188Type == "10" {
																if *serial_Slave.CJ188UnitType == 1 { //单位在前面
																	datareal = dataS[38:46]
																	unit = dataS[36:38]
																} else {
																	datareal = dataS[36:44]
																	unit = dataS[44:46]
																}
															}
														} else if *serial_Slave_Detail.CJ188CType == 3 { //结算日热量
															if cj188Type == "25" || cj188Type == "20" { //亿林专用
																if *serial_Slave.CJ188UnitType == 1 { //单位在前面
																	datareal = dataS[28:36]
																	unit = dataS[26:28]
																} else {
																	datareal = dataS[26:34]
																	unit = dataS[34:36]
																}
															}
														} else if *serial_Slave_Detail.CJ188CType == 4 { //当前热量
															if cj188Type == "25" || cj188Type == "20" { //亿林专用
																if *serial_Slave.CJ188UnitType == 1 { //单位在前面
																	datareal = dataS[38:46]
																	unit = dataS[36:38]
																} else {
																	datareal = dataS[36:44]
																	unit = dataS[44:46]
																}
															}
														} else if *serial_Slave_Detail.CJ188CType == 5 { //热功率
															if cj188Type == "25" || cj188Type == "20" { //亿林专用
																if *serial_Slave.CJ188UnitType == 1 { //单位在前面
																	datareal = dataS[48:56]
																	unit = dataS[46:48]
																} else {
																	datareal = dataS[46:54]
																	unit = dataS[54:56]
																}
															}
														} else if *serial_Slave_Detail.CJ188CType == 6 { //瞬时热量
															if cj188Type == "25" || cj188Type == "20" { //亿林专用
																if *serial_Slave.CJ188UnitType == 1 { //单位在前面
																	datareal = dataS[58:66]
																	unit = dataS[56:58]
																} else {
																	datareal = dataS[56:64]
																	unit = dataS[64:66]
																}
															}
														} else if *serial_Slave_Detail.CJ188CType == 7 { //当前累计流量
															if cj188Type == "25" || cj188Type == "20" { //亿林专用
																if *serial_Slave.CJ188UnitType == 1 { //单位在前面
																	datareal = dataS[68:76]
																	unit = dataS[66:68]
																} else {
																	datareal = dataS[66:74]
																	unit = dataS[74:76]
																}
															}
														} else if *serial_Slave_Detail.CJ188CType == 8 { //供水温度
															if cj188Type == "25" || cj188Type == "20" { //亿林专用
																datareal = dataS[76:82]
																unit = "110"
															}
														} else if *serial_Slave_Detail.CJ188CType == 9 { //回水温度
															if cj188Type == "25" || cj188Type == "20" { //亿林专用
																datareal = dataS[82:88]
																unit = "110"
															}
														}

														datarealC := ChangeStr(datareal) //获取反转后的数据
														value3 = datarealC

														if CJ188DecimalPointOffset >= 0 {
															if len(datarealC) < CJ188DecimalPointOffset {
																util.Error("cj188协议采集错误,ComName:" + Test[i2].ComName + ",返回参数解析失败 数据长度小于小数点偏移位数，请修改偏移位数")
																break
															} else {
																point := len(datarealC) - CJ188DecimalPointOffset
																end := len(datarealC)
																newData := datarealC[0:point] + "." + datarealC[point:end]
																v, _ := strconv.ParseFloat(newData, 32)
																f := float32(v)
																hexString = float32ToHex(f)
																// vString = fmt.Sprint(v)
																vString = fmt.Sprint(f)
															}
														} else {
															util.Error("cj188协议采集错误,ComName:" + Test[i2].ComName + ",返回参数解析失败,小数点偏移位数不能是负数，请修改偏移位数")
															break
														}
														unitName := GetUnitName(unit)
														vString = vString + " " + unitName
														//fmt.Println("item", item)
														AddDataSiemens(item, hexString, vString, value3)

													}
												}

												// for i := range util.DLT645Lock {
												if Test[i2].SerialID == serial_Slave.Serial_ID {
													//改变串口锁
													Test[i2].DLTisSend = true
												}
												// }
											}
										}
									}

									// SendDataByte(buffer)
									buffer = make([]byte, 0) // 重置 buffer
									receivedData = false

								}
							}
						} else {
							buf = buf[:n]
							ss := buf[n-1]
							s := fmt.Sprintf("%02X", ss)
							buffer = append(buffer, buf...)
							if s == "16" {
								//fmt.Println("buffer", buffer)
								//fmt.Println("BytesToHex", BytesToHex(buffer))
								if len(buffer) > 200 {
									util.Error("cj188协议采集错误,ComName:" + Test[i2].ComName + ",返回参数解析失败,data:" + BytesToHex(buffer))
									buffer = make([]byte, 0) // 重置 buffer
									receivedData = false
								} else {
									index := bytes.Index(buffer, []byte{104}) //从68开始
									if index != -1 {
										dataStr := BytesToHex(buffer[index : len(buffer)-2]) //获取字符串参数
										hexStr := CalculateChecksum(dataStr)                 //crc
										if hexStr == BytesToHex(buffer[len(buffer)-2:len(buffer)-1]) {
											receivedData = true
										}
									}
								}

							}

						}
					}
				}

			}()
		}
	}
}
func SendCj188Data(t dto.CollectSet) {
	go func() {
		j := 0
		for i := range Test {
			if t.DataID == Test[i].DataID {

				t = Test[i]
				j = i
				Test[i].IsEnd = false
				break
			}
		}
		if t.IsEnd {
			//fmt.Println("dlt645", t)
			//if t.CJ188Port != nil {
			//fmt.Println("进入", t.DataID, t.IsEnd)
			for _, data2 := range util.Serial_Slave {
				if data2.IsCollect == 1 {

					if data2.Serial_ID == t.DataID { //拿到同一个串口下的所有电表
						//fmt.Println("电表", data2)
						//获取该串口的广播位
						slaveID := ChangeStr(data2.ModbusSlaveID) //获取反转的地址位

						for _, item := range util.Serial_Slave_Detail {
							count := 0
							if item.Serial_ID == t.DataID && item.Serial_Slave_ID == data2.ID {
								for { //等待上一条发送的数据成功接收到返回数据，否则1s后发送下一条数据
									//fmt.Println("count", count)
									time.Sleep(100 * time.Millisecond)

									if Test[j].DLTisSend {
										//fmt.Println("util.DLT645Lock[i]", Test[j].DLTisSend)
										break
									}
									if count == 10 {
										Test[j].DLTisSend = true
										break
									}
									count++
									//fmt.Println("util.DLT645Lock[i]", Test[j].DLTisSend)
									//fmt.Println("count", count)
								}
								count = 0
								//锁住，等待返回成功或者定时结束 解锁
								Test[j].DLTisSend = false
								str := "68" + *data2.CJ188Type + slaveID + "0103" + *data2.CJ188DataIdentifier + "00"
								hexStr := CalculateChecksum(str)
								requestHex := str + hexStr + "16"
								requestBytes, err := hex.DecodeString(requestHex)
								if err != nil {
									Test[j].DLTisSend = true
									util.Error("cj188协议采集错误 ComName:" + t.ComName + "设备名称：" + data2.Name + ",DecodeStringerr：" + err.Error())

								}
								//发送数据
								// fmt.Println("dlt645发送参数：" + requestHex)
								// fmt.Println("data:", util.DLT645Data[i].CJ188Port)
								_, err = Test[j].CJ188Port.Write(requestBytes)
								if err != nil {
									Test[j].DLTisSend = true
									//stopTimerCh <- struct{}{}
									util.Error("cj188协议采集错误,重连中 ComName:" + t.ComName + "设备名称：" + data2.Name + ",Writeerr：" + err.Error())
									Cj188Restart(t.DataID)
								}

							}
						}
						time.Sleep(2 * time.Second)
					} else {
						logStr := "Name:" + data2.Name + ",已配置不进行采集"
						util.IsCollectLog(logStr)
					}
				}
			}
			for i := range Test {
				if t.DataID == Test[i].DataID {
					Test[i].IsEnd = true
					break
				}
			}
		} else {
			//fmt.Println("当前采集未结束", t.DataID, t.IsEnd)
			return
		}

	}()
}

// 解析cj188返回参数
func analysisDataCJ188(dataStr string) string {
	re := regexp.MustCompile("68(.+)")
	match := re.FindStringSubmatch(dataStr)
	if len(match) == 0 {
		//ut
		return ""
	}
	return match[1]
	//str := match[1] //68之后的参数  10423000061502008116901F00000200002C999999992C9999999999999900003A16
}

func GetUnitName(unit string) string {
	switch unit {
	case "02":
		return "Wh"
	case "05":
		return "KWh"
	case "08":
		return "MWh"
	case "0A":
		return "MWh * 100"
	case "01":
		return "J"
	case "0B":
		return "KJ"
	case "0E":
		return "MJ"
	case "11":
		return "GJ"
	case "13":
		return "GJ * 100"
	case "14":
		return "W"
	case "17":
		return "KW"
	case "1A":
		return "MW"
	case "29":
		return "L"
	case "2C":
		return "m^3"
	case "32":
		return "L/h"
	case "35":
		return "m^3/h"
	case "110":
		return "℃"
	default:
		return "单位错误"
	}

}
